#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
from mutagen.id3 import ID3, TIT2, TPE1, TALB, TCON, TCOM, TYER, TRCK, Encoding
from mutagen.mp3 import MP3

# 全局统计变量
stats = {
    'success': [],
    'failed' : [],
    'skipped': [],    # 无标签
    'passed' : []     # 无需修复
}
def decode_gb_maybe(text):
    """
    尝试将可能是 GBK 编码但被误读为 Latin-1/CP1252 的字符串还原为正确中文。
    如果失败，返回原始文本。
    """
    if not isinstance(text, str):
        return text

    # 常见错误：GBK 字节被当作 Latin-1 解码成乱码字符串
    # 我们尝试反向操作：用 latin1 编回去得到原始字节，再用 gbk 解码
    try:
        return text.encode('latin1').decode('gbk')
    except (UnicodeEncodeError, UnicodeDecodeError):
        pass

    # 有些系统可能用 cp1252
    try:
        return text.encode('cp1252').decode('gbk')
    except (UnicodeEncodeError, UnicodeDecodeError):
        pass

    # 无法修复，返回原样
    return text

def fix_tag_encoding(filepath):
    try:
        audio = MP3(filepath, ID3=ID3)
    except Exception as e:
        print(f"[error] 无法读取 {filepath}: {e}")
        stats['failed'].append((filepath, str(e)))
        return False

    if audio.tags is None:
        print(f"[ skip] {filepath} 无 ID3 标签")
        stats['skipped'].append(filepath)
        return False

    # 支持修复的常用帧（可扩展）
    tag_map = {
        'TIT2': TIT2,  # 标题
        'TPE1': TPE1,  # 艺术家（歌手）
        'TALB': TALB,  # 专辑
        'TCON': TCON,  # 流派
        'TCOM': TCOM,  # 作曲
        'TYER': TYER,  # 年份
        'TRCK': TRCK,  # 音轨号
    }

    modified = False
    for frame_id, frame_class in tag_map.items():
        if frame_id in audio.tags:
            raw_value = str(audio.tags[frame_id])
            fixed_value = decode_gb_maybe(raw_value)

            # 如果内容有变化，才更新（避免无意义写入）
            if fixed_value != raw_value:
                # 使用 UTF-8 编码写回
                audio.tags[frame_id] = frame_class(encoding=Encoding.UTF8, text=fixed_value)
                modified = True
                print(f"[  fix] {filepath} | {frame_id}: '{raw_value}' → '{fixed_value}'")

    if modified:
        try:
            audio.save()
            print(f"[ save] 标签已更新为 UTF-8: {filepath}")
            stats['success'].append(filepath)
            return True
        except Exception as e:
            print(f"[error] 保存失败 {filepath}: {e}")
            stats['failed'].append((filepath, str(e)))
            return False
    else:
        print(f"[ pass] 无需修复 {filepath}")
        stats['passed'].append(filepath)
        return False

def print_summary():
    print("\n" + "="*40 + " [Summary] " + "="*40)
    print(f" 成功修复: {len(stats['success']):>5}")
    print(f" 无需修复: {len(stats['passed']):>5}")
    print(f" 没有标签: {len(stats['skipped']):>5}")
    for f in stats['skipped']:
        print(f"  - {f}")
    print(f" 修复失败: {len(stats['failed']):>5}")
    for f, err in stats['failed']:
        print(f"  - {f} | 错误: {err}")

    total = len(stats['success']) + len(stats['passed']) + len(stats['skipped']) + len(stats['failed'])
    print("\n" + "-"*70)
    print(f"总计处理: {total:>5}")

def main():
    if len(sys.argv) != 2:
        print("Usage: python mp3_fix_tags.py <mp3 file or directory>")
        print("功能: 将 MP3 的 ID3 标签中可能为 GBK 编码的文本转为 UTF-8")
        return

    path = sys.argv[1]

    if os.path.isfile(path):
        if path.lower().endswith('.mp3'):
            fix_tag_encoding(path)
        else:
            print("ERROR: 输入文件不是 MP3 文件")
    elif os.path.isdir(path):
        for root, _, files in os.walk(path):
            for f in files:
                if f.lower().endswith('.mp3'):
                    fix_tag_encoding(os.path.join(root, f))
    else:
        print("ERROR: 路径不存在")
        return
    
    print_summary()

if __name__ == "__main__":
    main()
